﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Kinect;

namespace KinectedMusic.Kinect
{
    public class Controller
    {
        // TODO: put in manager?
        private ColorImageFormat colorImageFormat = ColorImageFormat.RgbResolution1280x960Fps12;

        public KinectSensor KinectSensor { get; private set; }
        public BoundingBox BoundingBox { get; private set; }
        public PostureDetector PostureDetector { get; private set; }
        public GestureDetector GestureDetector { get; private set; }

        private List<ISkeletonWork> skeletonWorkers;

        public event Action<ColorImageFrame> ImageSource;
        public event Action<ColourPerson> Person;


        public Controller()
        {
            SetupKinect();
            BoundingBox = new BoundingBox();
            PostureDetector = new PostureDetector();
            GestureDetector = new GestureDetector();

            skeletonWorkers = new List<ISkeletonWork>();
            skeletonWorkers.Add(GestureDetector);
        }

        private void SetupKinect()
        {
            if (KinectSensor.KinectSensors.Count == 0)
            {
                ;
            }
            else
            {
                this.KinectSensor = KinectSensor.KinectSensors[0];
                this.KinectSensor.ColorStream.Enable(colorImageFormat);
                this.KinectSensor.DepthStream.Enable();
                this.KinectSensor.SkeletonStream.Enable();
                this.KinectSensor.SkeletonStream.AppChoosesSkeletons = true;

                var parameters = new TransformSmoothParameters
                {
                    Smoothing = 0.3f,
                    Correction = 0.0f,
                    Prediction = 0.0f,
                    JitterRadius = 1.0f,
                    MaxDeviationRadius = 0.5f
                };
                this.KinectSensor.SkeletonStream.Enable(parameters);

                this.KinectSensor.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(AllFramesReady);
                this.KinectSensor.Start();
            }
        }

        private void AllFramesReady(object sender, AllFramesReadyEventArgs e)
        {
            //bool receivedData = false;
            using (ColorImageFrame color = e.OpenColorImageFrame())
            {
                if (color == null)
                {
                    return;
                }
                //TODO: only call when handlers, change to event args etc
                ImageSource(color);
            }

            Skeleton skeleton = BoundingBox.TrackSkelton(e, this.KinectSensor);

            if (skeleton == null)
            {
                return;
            }

            PostureStatus posture = PostureDetector.DetectPosture(skeleton);


            foreach (ISkeletonWork skeletonWork in skeletonWorkers)
            {
                skeletonWork.Work(skeleton, posture);
            }

            using (DepthImageFrame depth = e.OpenDepthImageFrame())
            {
                if (depth == null)
                {
                    return;
                }
                Person(new ColourPerson(depth, skeleton, colorImageFormat));
            }
        }

 
        // TODO: How to stop Kinect
        public void Terminate()
        {
            KinectSensor.Stop();
            KinectSensor.Dispose();
            KinectSensor = null;
        }
    }
}
